package org.michael.u.brg.by.gwtPlay.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.dom.client.*;
import com.google.gwt.i18n.client.*;
import com.google.gwt.user.client.*;
import com.google.gwt.user.client.Random;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.*;

import java.util.*;

/**
 * @author michaelb Michael Bergens
 */
public class StockWatcher implements EntryPoint {
    static final double MAX_PRICE = 100.0;
    static final double MAX_CHANGE = 0.02;
    // GWT can't handle this
//    static final MathContext STOCK_ROUNDING = new MathContext(2, RoundingMode.HALF_UP);

    private static class StockData {
        double price;
        double change;

        private StockData() {
            this.price = 0.0;
            this.change = 0.0;
        }

        double getChangePercent() {
            return 100.0 * change / price;
        }
    }

    public static class RowButton extends Button {
        final String symbol;

        private RowButton(final String html, final String symbol) {
            super(html);
            this.symbol = symbol;
        }
    }

    private FlexTable stocksTable;
    private TextBox newSymbolTextBox;
    private Map<String, StockData> stocks = new HashMap<String, StockData>();
    private Label lastUpdatedLabel;

    private void addStock() {
        final String symbol = newSymbolTextBox.getText().toUpperCase().trim();
        newSymbolTextBox.setFocus(true);
        if (symbol.matches("^[0-9A-Z\\.]{1,10}$")) {
            newSymbolTextBox.setText("");

            if (stocks.containsKey(symbol)) {
                Window.alert("Already in the table");
            }
            else {
                int row = stocksTable.getRowCount();
                stocks.put(symbol, new StockData());
                stocksTable.setText(row, 0, symbol);
                final RowButton removeOne = new RowButton("<font color=\"red\"><sup>x</sup></font>", symbol);
                removeOne.addClickHandler(new ClickHandler() {
                    @Override
                    public void onClick(ClickEvent event) {
                        final Object source = event.getSource();
                        if (source != null && source instanceof RowButton) {
                            RowButton me = (RowButton) source;
                            boolean isFound = false;
                            int rowIndex = 0;
                            for (; rowIndex < stocksTable.getRowCount(); rowIndex++) {
                                final String rowSymbol = stocksTable.getText(rowIndex, 0);
                                if (rowSymbol.equals(me.symbol)) {
                                    isFound = true;
                                    break;
                                }
                            }
                            if (isFound) {
                                stocks.remove(me.symbol);
                                stocksTable.removeRow(rowIndex);
                                // don't worry about concurrency, it runs in JavaScript on the browser.
                            }
                        }
                    }
                });
                stocksTable.setWidget(row, 3, removeOne);
            }

        }
        else {
            Window.alert('\"' + symbol + "\" is not a valid symbol");
            newSymbolTextBox.selectAll();
        }
    }

    public void onModuleLoad() {

        final RootPanel rootPanel = RootPanel.get();
        final VerticalPanel mainPanel = new VerticalPanel();
        rootPanel.add(mainPanel, 10, 10);
        mainPanel.setSize("600px", "400px");
        stocksTable = new FlexTable();
        stocksTable.setHTML(0, 0, "Symbol&nbsp;&nbsp;");
        stocksTable.setHTML(0, 1, "Price&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
        stocksTable.setHTML(0, 2, "Change&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
        stocksTable.setHTML(0, 3, "Remove");
        stocksTable.setCellPadding(1);
        stocksTable.setCellSpacing(2);
                stocksTable.setStyleName("panel flexTable");
        mainPanel.add(stocksTable);
        final HorizontalPanel addPanel = new HorizontalPanel();
        mainPanel.add(addPanel);
        newSymbolTextBox = new TextBox();
        addPanel.add(newSymbolTextBox);
        final Button addButton = new Button("Add");
        addPanel.add(addButton);
        lastUpdatedLabel = new Label("                  ");
        mainPanel.add(lastUpdatedLabel);
        newSymbolTextBox.addKeyPressHandler(new KeyPressHandler() {
            @Override
            public void onKeyPress(KeyPressEvent event) {
                if (event.getCharCode() == KeyCodes.KEY_ENTER) {
                    addStock();
                }
            }
        });
        addButton.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                addStock();
            }
        });
        final Timer refreshTimer = new Timer() {
            @Override
            public void run() {
                refreshStocks();
            }
        };
        refreshTimer.scheduleRepeating(5000);
    }

    private void refreshStocks() {
        for (StockData stock : stocks.values()) {
            stock.price = Random.nextDouble() * MAX_PRICE;
            stock.change = (Random.nextDouble() * 2.0 - 1.0) * MAX_CHANGE * stock.price;
        }
        updateData();
        lastUpdatedLabel.setText("Last update : "
            + DateTimeFormat.getMediumDateTimeFormat().format(new Date()));
        lastUpdatedLabel.setStyleName("lastUpdateLabel");
    }

    private void updateData() {
        for (int rowIndex = 0; rowIndex < stocksTable.getRowCount(); rowIndex++) {
            final String symbol = stocksTable.getText(rowIndex, 0);
            final StockData stock = stocks.get(symbol);
            if (stock != null) {
                String priceText = NumberFormat.getFormat("#,##0.00").format(stock.price);
                NumberFormat changeFormat = NumberFormat.getFormat("+#,##0.00;-#,##0.00");
                String changeText = changeFormat.format(stock.change);
                String changePercentText = changeFormat.format(stock.getChangePercent());
                stocksTable.setText(rowIndex, 1, priceText);
                stocksTable.setText(rowIndex, 2, changeText + " (" + changePercentText + "%)");
            }
            // don't worry about concurrency, it runs in JavaScript on the browser.
        }
    }
}
